package com.vegetable.modules.service.inbound.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.vegetable.common.constant.CommonConstant;
import com.vegetable.common.utils.Constant;
import com.vegetable.common.utils.PageUtils;
import com.vegetable.common.utils.Query;
import com.vegetable.common.utils.R;
import com.vegetable.modules.entity.baseData.AccountDetails;
import com.vegetable.modules.entity.baseData.ProductSpec;
import com.vegetable.modules.entity.baseData.Products;
import com.vegetable.modules.entity.finance.po.PackCanPayPO;
import com.vegetable.modules.entity.inbound.*;
import com.vegetable.modules.entity.inbound.po.PackDeliverySequencePO;
import com.vegetable.modules.entity.inbound.vo.PackDeliverySequenceVO;
import com.vegetable.modules.entity.outbound.SalesOrderDetailStock;
import com.vegetable.modules.entity.stock.Stock;
import com.vegetable.modules.entity.stock.to.StockFlowDTO;
import com.vegetable.modules.mapper.inbound.PackDeliveryMapper;
import com.vegetable.modules.service.baseData.IAccountDetailsService;
import com.vegetable.modules.service.baseData.IProductSpecService;
import com.vegetable.modules.service.baseData.IProductsService;
import com.vegetable.modules.service.inbound.*;
import com.vegetable.modules.service.outbound.ISalesOrderDetailStockService;
import com.vegetable.modules.service.stock.IStockFlowService;
import com.vegetable.modules.service.stock.IStockService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 加工打包 服务实现类
 * </p>
 *
 * @author wangruijie
 * @since 2024-03-21
 */
@Slf4j
@Service
@AllArgsConstructor
public class PackDeliveryServiceImpl extends ServiceImpl<PackDeliveryMapper, PackDelivery> implements IPackDeliveryService {

    // 订单费用
    private IOrderCostService orderCostService;
    // 商品明细
    private IPackDeliveryDetailService deliveryDetailService;
//    // 商品明细的包装材料
//    private IPackDeliveryDetailMaterialService materialService;

    private ISalesOrderDetailStockService detailStockService;
    // 产地商品
    private IProductsService productsService;
    // 库存表
    private IStockService stockService;
    // 库存流水
    private IStockFlowService iStockFlowService;
    // 往来明细
    private IAccountDetailsService accountDetailsService;
    // 商品规格
    private IProductSpecService specService;

    private IStockService iStockService;
    // 订单商品包装
    private IAgentDeliveryDetailPackService detailPackService;

    private IPackDeliveryTeamService packDeliveryTeamService;

    /**
     * 加工打包列表查询
     * @param params
     * @return
     */
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        String docNo = (String)params.get("docNo");
        String startTime = (String)params.get("startTime");
        String endTime = (String)params.get("endTime");
        String state = (String)params.get("state");
        String commodityNames = (String) params.get("commodityNames");
        String finishCommodityName = (String) params.get("finishCommodityName");
        IPage<PackDelivery> page = this.page(
                new Query<PackDelivery>().getPage(params),
                new QueryWrapper<PackDelivery>()
                        .between(StringUtils.isNotBlank(startTime), "order_time", DateUtil.beginOfDay(DateUtil.parseDate(startTime)), DateUtil.endOfDay(DateUtil.parseDate(endTime)))
                        .eq(ObjectUtils.isNotEmpty(params.get("teamId")),"team_id", params.get("teamId"))
                        .eq(StringUtils.isNotBlank(docNo),"doc_no", docNo)
                        .eq(StringUtils.isNotBlank(state),"state", state)
                        .like(StringUtils.isNotBlank(commodityNames),"commodity_names", commodityNames)
                        .like(StringUtils.isNotBlank(finishCommodityName),"finish_commodity_name", finishCommodityName)
                        .orderByDesc("order_time", "create_time")
        );

        return new PageUtils(page);
    }

    /**
     * 详情加工打包
     * @param id null
     * @return R
     * @author wrj
     * @since 2024/3/21 下午4:35
     */
    @Override
    public R detailPackDelivery(Long id) {
        PackDelivery delivery = baseMapper.selectById(id);
        if (delivery == null){
            return R.fail("订单不存在");
        }
        // 领料耗用的商品明细
        List<PackDeliveryDetail> commodities = new ArrayList<>();
        // 生产完工的商品明细
        List<PackDeliveryDetail> finishCommodities = new ArrayList<>();
        // 查询原订单的其他费用
        log.info("查询原订单的其他费用:{}", delivery.getDocNo());
        QueryWrapper<OrderCost> orderCostQueryWrapper = new QueryWrapper();
        orderCostQueryWrapper.eq("main_id", delivery.getId());
        List<OrderCost> orderCosts = orderCostService.getBaseMapper().selectList(orderCostQueryWrapper);
        if (CollectionUtils.isNotEmpty(orderCosts)){
            delivery.setCosts(orderCosts);
        }
        // 查询原订单的商品
//        QueryWrapper<PackDeliveryDetail> detailQuery = new QueryWrapper();
//        detailQuery.eq("delivery_id", delivery.getId());
        List<PackDeliveryDetail> details = deliveryDetailService.selectByOrderId(delivery.getId());
        if (CollectionUtils.isNotEmpty(details)){
            for (PackDeliveryDetail detail: details) {
//                Products products = productsService.getById(detail.getCommodityId());
//                detail.setCommodityCode(products.getCommonCode());

                // 查询原订单的商品的其他费用
                log.info("查询原订单的商品的其他费用:{}", JSON.toJSONString(detail.getId()));
                QueryWrapper<OrderCost> detailCost = new QueryWrapper();
                detailCost.in("main_id", detail.getId());
                List<OrderCost> costs = orderCostService.getBaseMapper().selectList(detailCost);
                detail.setCosts(costs);
                // 查询原订单的商品下的包装材料
//                QueryWrapper<AgentDeliveryDetailPack> materialQuery = new QueryWrapper();
//                materialQuery.eq("detail_id", detail.getId());
                if (detail.getDetailType().intValue() == 0){
                    String packageCost = detail.getPackageCost();
                    List<AgentDeliveryDetailPack> materialList = JSONArray.parseArray(packageCost, AgentDeliveryDetailPack.class);
                    if(CollectionUtil.isNotEmpty(materialList)){
                        for(AgentDeliveryDetailPack pack : materialList){
                            pack.setNumber(NumberUtil.mul(pack.getStandardNumber(), detail.getNumber()));
                            pack.setMoney(NumberUtil.mul(pack.getNumber(), pack.getUnitPrice()));
                        }
                        detail.setMaterials(materialList);
                        detail.setPackageCostForSales(materialList.stream().map(AgentDeliveryDetailPack::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add));
                    }
                    commodities.add(detail);
                }else {
                    List<AgentDeliveryDetailPack> materialList = detailPackService.selectByDetailId(detail.getId());
                    detail.setMaterials(materialList);
                    detail.setPackageCostForSales(materialList.stream().map(AgentDeliveryDetailPack::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add));
                    finishCommodities.add(detail);
                }
            }
            delivery.setCommodities(commodities);
            PackDeliveryDetail finished = finishCommodities.get(0);
            // 成品包装费用
            BigDecimal fPCost = finished.getPackageCostForSales();
            // 材料包装费用
            BigDecimal mPCost = commodities.stream().map(PackDeliveryDetail::getPackageCostForSales).reduce(BigDecimal.ZERO, BigDecimal::add);
            // 材料蔬菜费用
            BigDecimal mWCost = commodities.stream().map(pd -> NumberUtil.mul(pd.getCostWeight(), NumberUtil.mul(pd.getWeight(), NumberUtil.add(pd.getLossRate(), 1)))).reduce(BigDecimal.ZERO, BigDecimal::add);
            finished.setGoodsMoney(NumberUtil.add(fPCost, mPCost, mWCost));
            delivery.setFinishCommodities(finishCommodities);
        }
        List<StockFlowDTO> flows = iStockFlowService.queryOutFlowByOrderNo(delivery.getDocNo(), delivery.getId());
        delivery.setStockFlows(flows);
        List<Stock> stocks = stockService.queryStockByOrderId(delivery.getId());
        if(CollectionUtil.isNotEmpty(stocks)){
            for(Stock stock : stocks){
                String packageCost = stock.getPackageCost();
                List<AgentDeliveryDetailPack> array = JSONArray.parseArray(packageCost, AgentDeliveryDetailPack.class);
                // 包装总费用
                BigDecimal packageCostTotal = BigDecimal.ZERO;
                // 每件商品包装费用
                BigDecimal packageCostPer = BigDecimal.ZERO;
                // 每公斤商品的包装费用
                BigDecimal packageCostWeight = BigDecimal.ZERO;
                if(CollectionUtil.isNotEmpty(array)){
                    packageCostTotal = array.stream().map(flow -> NumberUtil.mul(flow.getUnitPrice(), flow.getNumber())).reduce(BigDecimal.ZERO, BigDecimal::add);
                    packageCostPer = array.stream().map(flow -> NumberUtil.mul(flow.getUnitPrice(), flow.getStandardNumber())).reduce(BigDecimal.ZERO, BigDecimal::add);
                    packageCostWeight = NumberUtil.div(packageCostTotal, stock.getInitWeight());
                }
                stock.setPackageCostForSales(packageCostPer.doubleValue());
                stock.setCost(NumberUtil.add(stock.getCostWeight(), packageCostWeight));
            }
        }
        delivery.setStocks(stocks);
        List<PackDeliveryTeam> teams = packDeliveryTeamService.selectByDeliveryId(id);
        delivery.setTeams(teams);
        return R.data(delivery);
    }

    /**
     * 新增加工打包
     * @param packDelivery null
     * @return R
     * @author wrj
     * @since 2024/3/21 下午4:35
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R saveOrEdit(PackDelivery packDelivery) throws Exception {
        if(ObjectUtil.isNull(packDelivery.getPackType())){
            throw new RuntimeException("加工类型没有选择，无法确定原料包装成本归属");
        }
        // 新增加工打包主表
        Set<String> commodityNames = new HashSet();
        Set<String> finishCommodityNames = new HashSet();
//        if (CollectionUtils.isEmpty(packDelivery.getCommodities())){
//            throw new Exception("商品列表不能为空");
//        }
        Integer number = 0;
        BigDecimal weight = BigDecimal.ZERO;
        // 耗用
        for (PackDeliveryDetail deliveryDetail: packDelivery.getCommodities()) {
            commodityNames.add(deliveryDetail.getCommodityName());
            number = number + deliveryDetail.getNumber();
            weight = weight.add(deliveryDetail.getWeight());
        }
        Integer inNumber = 0;
        BigDecimal inWeight = BigDecimal.ZERO;
        // 生产加工商品
        for (PackDeliveryDetail deliveryDetail: packDelivery.getFinishCommodities()) {
            inNumber = inNumber+deliveryDetail.getNumber();
            inWeight = inWeight.add(deliveryDetail.getWeight());
            finishCommodityNames.add(deliveryDetail.getCommodityName());
        }
        packDelivery.setNumber(number);
        packDelivery.setWeight(weight);
        packDelivery.setFinishNumber(inNumber);
        packDelivery.setFinishWeight(inWeight);
        packDelivery.setCommodityNames(String.join("|", commodityNames));
        packDelivery.setFinishCommodityName(String.join("|", finishCommodityNames));
        if (packDelivery.getId() == null){
            packDelivery.setDocNo(CommonConstant.JGDB+ baseMapper.getNextCode());
            save(packDelivery);
        }else {
            // 修改主表数据
            updateById(packDelivery);
            // 删除其他费用，商品信息，已经商品下的信息
            deleteMethod(packDelivery);
        }
        // 加工打包主键
        Long mainId = packDelivery.getId();
        // 把加工单价弄到加工组去
        Optional<AgentDeliveryDetailPack> opt = packDelivery.getFinishCommodities().get(0).getMaterials().stream().filter(el -> el.getCostClauseName().equals("加工单价")).findAny();
        if(opt.isPresent()){
            List<PackDeliveryTeam> teams = new ArrayList<>();
            PackDeliveryTeam team = new PackDeliveryTeam();
            team.setDeliveryId(packDelivery.getId());
            team.setTeamId(packDelivery.getTeamId());
            team.setTeamName(packDelivery.getTeamName());
            team.setNumber(packDelivery.getFinishNumber());
            team.setUnitPrice(opt.get().getUnitPrice());
            team.setMoney(opt.get().getMoney());
            teams.add(team);
            packDeliveryTeamService.add(teams);
        }

        // 保存订单下明细，其他费用
        return saveDetailInfo(mainId, packDelivery);
    }

    /**
     * 提交加工打包
     * @param packDelivery null
     * @return R
     * @author wrj
     * @since 2024/3/21 下午4:35
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R submitPackDelivery(PackDelivery packDelivery) throws Exception {
        PackDelivery exist = getById(packDelivery.getId());
        if(Objects.isNull(exist)){
            throw new Exception("加工单不存在.");
        }
        if(exist.getState() == 1){
            throw new Exception("加工单已经完成，不要重复提交");
        }
        // 加工成品
        List<PackDeliveryDetail> finishCommodities = packDelivery.getFinishCommodities();
        if(CollectionUtil.isEmpty(finishCommodities)){
            throw new Exception("加工成品不能为空");
        }
        if(finishCommodities.size() > 1){
            throw new Exception("每次只能加工一种商品");
        }
        // 生成入库库存
        PackDeliveryDetail detail =  packDelivery.getFinishCommodities().get(0);
        // 根据商品id查询商品
        Products products = productsService.getById(detail.getCommodityId());
        if (products == null){
            throw new Exception("生成的成品不存在，请认真检查");
        }
        // 新增/修改数据
        packDelivery.setState(1);
        saveOrEdit(packDelivery);
        // 根据库存id判断生产领料耗用是否还够扣除
        checkStockNumber(packDelivery);
        // 生产完工成品进入库存
        saveInStock(packDelivery, products);
        // 生成该班组下的往来明细
        saveAccountDetails(packDelivery);

        return R.data(packDelivery.getId());
    }

    /**
     * 校验领料耗用的商品明细:库存是否满足扣除
     * 扣除生产领料耗用库存
     * @param packDelivery
     * @throws Exception
     */
    private void checkStockNumber(PackDelivery packDelivery) throws Exception {
        List<SalesOrderDetailStock> detailStocks = new ArrayList<>();
        for (PackDeliveryDetail detail : packDelivery.getCommodities()) {
            Stock stock = stockService.getById(detail.getStockId());
            if (stock == null){
                throw new Exception("库存不存在或者已被其他订单使用");
            }
            BigDecimal rate = detail.getLossRate();
            // 标重
//            BigDecimal standard = cons.getStandard();
            // 出库重量
//            BigDecimal weight = NumberUtil.equals(BigDecimal.ZERO, standard) ? cons.getWeight() : NumberUtil.mul(standard, number);
            // 实际出库重量 = 输入的重量 * （ 1 + 耗损比率）
            BigDecimal actWeight = NumberUtil.mul(detail.getWeight(), NumberUtil.add(rate, 1));
            BigDecimal changeNum = NumberUtil.equals(stock.getStandard(), BigDecimal.ZERO) ? detail.getWeight() : new BigDecimal(detail.getNumber());
            // 实际出库数量
            Integer actNumber = detail.getNumber();
            // 数量，重量均满足
            if ((stock.getNumber() < actNumber)
                || (stock.getWeight().compareTo(actWeight) < 0)){
                throw new Exception("耗用商品"+detail.getCommodityName()+"库存数量或者重量不足，请检查");
            }
            log.info("加工打包的领料耗用扣除库存前 ：{}", JSON.toJSONString(stock));
            stock.setNumber(stock.getNumber() - actNumber);
            BigDecimal weight = stock.getWeight();
            weight = weight.subtract(actWeight);
            stock.setWeight(weight);
            // 本次成本 = 重量 * 库存的（成本/重量）
            BigDecimal cost_sub = stock.getCostWeight().multiply(actWeight);
            BigDecimal cost = stock.getCost();
            cost = cost.subtract(cost_sub);
            stock.setCost(cost);
            log.info("加工打包的领料耗用扣除库存后 ：{}", JSON.toJSONString(stock));
            if (stock.getNumber() >= 0 || NumberUtil.isGreaterOrEqual(stock.getWeight(), BigDecimal.ZERO)){
                stockService.updateById(stock);
                iStockFlowService.addStockFlow(stock, Constant.StockFlowType.WORK_OUT.getValue(), changeNum, stock.getStorageOrderNo(), Constant.StockFlowType.WORK_OUT.getName(), packDelivery.getOrderTime());
            }else {
                throw new Exception("库存不够 请重试");
//                stockService.removeById(detail.getStockId());
            }

            Integer inNumber = actNumber;
            BigDecimal inWeight = actWeight;
            if((ObjectUtil.isNotNull(inNumber) && inNumber != 0) || (ObjectUtil.isNotNull(inWeight) && !NumberUtil.equals(inWeight, BigDecimal.ZERO))){
                SalesOrderDetailStock detailStock = new SalesOrderDetailStock();
                detailStock.setOrderId(detail.getDeliveryId());
                detailStock.setDetailId(detail.getId());
                detailStock.setType(2);
                detailStock.setNumber(inNumber);
                detailStock.setWeight(inWeight);
                detailStock.setStockId(stock.getId());
                detailStock.setStockBatchNo(stock.getStockBatchNo());
                detailStocks.add(detailStock);
            }
        }
        detailStockService.saveOrUpdateBatch(detailStocks);
    }

    private void checkMaterial(List<AgentDeliveryDetailPack> packs) throws Exception {

    }

    /**
     * 生产完工商品入库
     * @param packDelivery null
     * @return void
     * @author wrj
     * @since 2024/3/22 上午11:40
     */
    private void saveInStock(PackDelivery packDelivery, Products products) throws Exception {
        // 生产领料耗材
        List<PackDeliveryDetail> consumables = packDelivery.getCommodities().stream().filter(dd -> dd.getDetailType() == 0).collect(Collectors.toList());
        // 总费用
        BigDecimal totalMoney = BigDecimal.ZERO;
        // 累加耗材的库存成本
        for (PackDeliveryDetail cons : consumables){
            // 商品库存
            Stock stock = iStockService.selectById(cons.getStockId());
            // 耗损比率
            BigDecimal rate = cons.getLossRate();
            BigDecimal actWeight = NumberUtil.mul(cons.getWeight(), NumberUtil.add(rate, 1));
            // 所选库存的成本单价（裸价 + 其他费用）
            BigDecimal costWeight = stock.getCostWeight();
            totalMoney = NumberUtil.add(totalMoney, NumberUtil.mul(costWeight, actWeight));
        }
        // 累加其他费用
        List<OrderCost> costs = packDelivery.getCosts();
        if(CollectionUtil.isNotEmpty(costs)){
            for (OrderCost cost : costs){
                totalMoney = NumberUtil.add(totalMoney, cost.getMoney());
            }
        }
        // 生成入库库存
        PackDeliveryDetail detail =  packDelivery.getFinishCommodities().get(0);
        String specsName = null;
        if (ObjectUtil.isNotNull(detail.getSpecsId())){
            ProductSpec productSpec = specService.getById(detail.getSpecsId());
            specsName = productSpec.getName();
        }
        Date orderTime = packDelivery.getOrderTime();
        String docNo = packDelivery.getDocNo();
        // 计算成本
        String agentName = Constant.StockFlowType.WORK_IN.getName();
        // 成品的包装材料
        List<AgentDeliveryDetailPack> finishMaterials = detail.getMaterials();
        // 归属蔬菜成本的包装
        List<AgentDeliveryDetailPack> gMaterial = new ArrayList<>();
        // 归属包装成本的包装
        List<AgentDeliveryDetailPack> pMaterial = new ArrayList<>();
        // 如果包装材料不是空的，按照归属分类
        if(CollectionUtil.isNotEmpty(finishMaterials)){
            Map<Integer, List<AgentDeliveryDetailPack>> listMap = finishMaterials.stream().collect(Collectors.groupingBy(r -> r.getPackBelong()));
            gMaterial = CollectionUtil.isEmpty(listMap.get(0)) ? gMaterial : listMap.get(0);
            pMaterial = CollectionUtil.isEmpty(listMap.get(1)) ? pMaterial : listMap.get(1);
        }
        // 如果归属蔬菜成本的包装材料不为空，则需要把这部分钱合计到蔬菜成本中
        if(CollectionUtil.isNotEmpty(gMaterial)){
            BigDecimal packageCost = gMaterial.stream().map(AgentDeliveryDetailPack::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
            // 累加包装费用
            totalMoney = totalMoney.add(packageCost);
        }
        // 如果是正常加工，原料包装需要合计到成品蔬菜成本中
        if(packDelivery.getPackType() == 1){
            for (PackDeliveryDetail cons : consumables){
                // 包装材料也要加入到合成品的成本中
                BigDecimal packageCost = cons.getMaterials().stream().map(AgentDeliveryDetailPack::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
                // 累加包装费用
                totalMoney = totalMoney.add(packageCost);
            }
        }else if(packDelivery.getPackType() == 0){
            // 如果是平调，原料包装需要合计到成品包装成本中
            for (PackDeliveryDetail cons : consumables){
                pMaterial.addAll(cons.getMaterials());
            }
        }
        String packageCostStr = JSONArray.toJSONString(pMaterial);
        stockService.inStock(orderTime, totalMoney, products, detail.getSpecsId(), specsName, detail.getNumber(), detail.getWeight(), Constant.StockFlowType.WORK_IN.getValue(), Constant.WAREHOUSE_ID, Constant.WAREHOUSE_NAME, agentName, packageCostStr, docNo, packDelivery.getId(), detail.getId(), BigDecimal.ZERO);
    }

    /**
     * 新增班组的往来明细
     * @param packDelivery null
     * @return void
     * @author wrj
     * @since 2024/3/22 上午11:44
     */
    private void saveAccountDetails(PackDelivery packDelivery){
        // 生成班组的往来明细
        AccountDetails accountDetails = new AccountDetails();
        PackDeliveryDetail pd = packDelivery.getFinishCommodities().get(0);
        List<AgentDeliveryDetailPack> packs = pd.getMaterials();
        if(CollectionUtil.isNotEmpty(packs)){
            Optional<AgentDeliveryDetailPack> opt = packs.stream().filter(el -> el.getCostClauseName().equals("加工单价")).findAny();
            if(opt.isPresent()){
                accountDetails.setMoney(opt.get().getMoney());
            }
        }
        accountDetails.setStaffType(3); // 班组
        accountDetails.setPersonId(packDelivery.getTeamId());
        accountDetails.setDetailType(6); // 打包
        accountDetails.setOrderId(packDelivery.getId());
        accountDetails.setOrderTime(packDelivery.getOrderTime());
        accountDetails.setDocNo(packDelivery.getDocNo());
        log.info("加工打包保存班组的往来明细：{}", JSON.toJSONString(accountDetails));
        QueryWrapper<AccountDetails> wrapper2 = new QueryWrapper<>();
        wrapper2.lambda().eq(AccountDetails::getOrderId, packDelivery.getId());
        wrapper2.lambda().eq(AccountDetails::getStaffType, 3);
        wrapper2.lambda().eq(AccountDetails::getDetailType, 6);
        accountDetailsService.saveOrUpdate(accountDetails, wrapper2);
    }
    /**
     * 保存订单下明细，包装费用，其他费用
     * @param mainId
     * @param packDelivery
     * @return
     */
    private R saveDetailInfo(Long mainId, PackDelivery packDelivery){
        BigDecimal price_unit = BigDecimal.ZERO;
        try {
            price_unit = packDelivery.getMoney().divide(packDelivery.getWeight(), 2, RoundingMode.HALF_UP);
        }catch (Exception e){
            e.printStackTrace();
        }
        List<OrderCost> costs_all = new ArrayList<>();
        // 保存加工打包的其他费用
        log.info("保存加工打包的其他费用:{}", JSON.toJSONString(packDelivery.getDocNo()));
        if (CollectionUtils.isNotEmpty(packDelivery.getCosts())){
            for (OrderCost cost :packDelivery.getCosts()) {
                cost.setId(null);
                cost.setMainId(mainId);
                costs_all.add(cost);
            }
        }
        // 保存加工打包的商品
        log.info("保存加工打包的商品的耗用:{}", JSON.toJSONString(packDelivery.getDocNo()));
        List<PackDeliveryDetail> commodities = packDelivery.getCommodities();
        for (PackDeliveryDetail deliveryDetail: commodities) {
            // 商品金额+商品的其他费用 =总金额
            BigDecimal money = deliveryDetail.getGoodsMoney();
            if (CollectionUtils.isNotEmpty(deliveryDetail.getCosts())){
                for (OrderCost cost :deliveryDetail.getCosts()) {
                    money = money.add(cost.getMoney());
                }
            }
            deliveryDetail.setId(null);
            deliveryDetail.setCost(price_unit.multiply(deliveryDetail.getWeight()));
            deliveryDetail.setMoney(money);
            deliveryDetail.setDeliveryId(mainId);
            deliveryDetailService.save(deliveryDetail);
        }

        // 保存加工打包的商品
        log.info("保存加工打包的商品的完工商品:{}", JSON.toJSONString(packDelivery.getDocNo()));
        List<PackDeliveryDetail> finishCommodities = packDelivery.getFinishCommodities();
        for (PackDeliveryDetail finishCommodity : finishCommodities) {
            // 商品金额+商品的其他费用 = 总金额
            BigDecimal money = finishCommodity.getGoodsMoney();
            if (CollectionUtils.isNotEmpty(finishCommodity.getCosts())){
                for (OrderCost cost :finishCommodity.getCosts()) {
                    money = money.add(cost.getMoney());
                }
            }
            finishCommodity.setId(null);
            finishCommodity.setCost(price_unit.multiply(finishCommodity.getWeight()));
            finishCommodity.setMoney(money);
            finishCommodity.setDeliveryId(mainId);
            deliveryDetailService.save(finishCommodity);
            // 商品id
            Long detailId = finishCommodity.getId();
            List<AgentDeliveryDetailPack> materials = finishCommodity.getMaterials();
            if (CollectionUtils.isNotEmpty(materials)){
                for (AgentDeliveryDetailPack material:materials) {
                    material.setId(null);
                    material.setOrderType(1);
                    material.setDetailId(detailId);
                }
            }
            log.info("保存打包加工的完成商品的商品材料：{}", JSON.toJSONString(materials));
            detailPackService.saveBatch(materials);

            // 保存加工打包的商品的其他费用
            log.info("保存加工打包的商品的其他费用:{}", JSON.toJSONString(packDelivery.getDocNo()));
            if (CollectionUtils.isNotEmpty(finishCommodity.getCosts())){
                for (OrderCost cost :finishCommodity.getCosts()) {
                    cost.setId(null);
                    cost.setMainId(finishCommodity.getId());
                    costs_all.add(cost);
                }
            }
            // 保存入库代办交货的商品包装关系表
//            log.info("保存加工打包的商品包装关系表:{}", JSON.toJSONString(packDelivery.getDocNo()));
//            if (CollectionUtils.isNotEmpty(finishCommodity.getMaterials())){
//                List<AgentDeliveryDetailPack> autoCosts = finishCommodity.getMaterials();
//                for (AgentDeliveryDetailPack autoCost: autoCosts) {
//                    autoCost.setId(null);
//                    autoCost.setOrderType(1);
//                    autoCost.setDetailId(finishCommodity.getId());
//                }
//                detailPackService.saveBatch(autoCosts);
//            }
        }
        if (CollectionUtils.isNotEmpty(costs_all)){
            orderCostService.saveBatch(costs_all);
        }
        return R.data(mainId);
    }

    /**
     * 删除加工打包
     * @param id null
     * @return R
     * @author wrj
     * @since 2024/3/21 下午4:35
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R deletePackDelivery(Long id) throws Exception {
        PackDelivery delivery = baseMapper.selectById(id);
        if (delivery == null){
            throw new Exception("订单不存在");
        }
        if (delivery.getState().intValue() == 2){
            throw new Exception("订单已完成，不允许删除");
        }

        baseMapper.deleteById(id);
        deleteMethod(delivery);
        // 释放库存
        stockService.releaseStock(delivery.getDocNo());
        return R.status(true);
    }

    @Override
    public List<PackDelivery> selectByIds(List<Long> orderIds) {
        return baseMapper.selectBatchIds(orderIds);
    }

    @Override
    public List<PackDelivery> selectByDocNoList(List<String> docNoList) {
        QueryWrapper<PackDelivery> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("doc_no", docNoList);
        return baseMapper.selectList(queryWrapper);
    }

    @Override
    public R lastOrder(Long id) {
        List<PackDeliveryDetail> details = new ArrayList<>();
        QueryWrapper<PackDeliveryDetail> wrapper = new QueryWrapper<>();
        wrapper.eq("commodity_id", id);
        wrapper.eq("detail_type", 1);
        wrapper.orderByDesc("create_time", "id");
        wrapper.last("limit 1");
        PackDeliveryDetail pd = deliveryDetailService.getBaseMapper().selectOne(wrapper);
        if(ObjectUtil.isNotNull(pd)){
            QueryWrapper<PackDeliveryDetail> dataWrapper = new QueryWrapper<>();
            dataWrapper.eq("delivery_id", pd.getDeliveryId());
            dataWrapper.eq("detail_type", 0);
            details = deliveryDetailService.getBaseMapper().selectList(dataWrapper);
        }
        return R.data(details);
    }

    @Override
    public IPage<PackDeliverySequenceVO> statisticsPackDelivery(PackDeliverySequencePO po) {
        IPage<PackDeliverySequenceVO> result = baseMapper.statisticsPackDelivery(new Page<>(po.getPage(), po.getLimit()), po);
        List<PackDeliverySequenceVO> vos = result.getRecords();
        if(CollectionUtil.isNotEmpty(vos)){
            List<Long> finishIds = vos.stream().map(PackDeliverySequenceVO::getFinishId).collect(Collectors.toList());
            List<AgentDeliveryDetailPack> detailPacks = detailPackService.selectByDetailIds(finishIds);
            for (PackDeliverySequenceVO vo : vos) {
                List<AgentDeliveryDetailPack> materialList = detailPacks.stream().filter(el -> el.getDetailId().equals(vo.getFinishId())).collect(Collectors.toList());
                vo.setFinishPackages(materialList);
                vo.setFinishPackageMoney(materialList.stream().map(AgentDeliveryDetailPack::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add));
                materialList.stream().filter(el -> el.getCostClauseName().equals("加工单价")).findFirst().ifPresent(el -> vo.setLaborCost(el.getMoney()));
            }
        }
        return result;
    }

    @Override
    public void checkOrderCostByStockId(Long stockId) {
        // 根据stockId查询关联的加工原料
        List<PackDeliveryDetail>  details = deliveryDetailService.selectByStockId(stockId);
        if(CollectionUtil.isEmpty(details)){
            log.info("根据{}没有查询到加工信息", stockId);
            return;
        }
        // 根据原料查询全部加工订单
        List<Long> packOrderIds = details.stream().map(PackDeliveryDetail::getDeliveryId).collect(Collectors.toList());
        for(Long packOrderId : packOrderIds){
            // 加工订单主表
            PackDelivery packOrder = baseMapper.selectById(packOrderId);
            // 加工订单明细
            List<PackDeliveryDetail> desList = deliveryDetailService.selectByOrderId(packOrderId);
            // 成品
            PackDeliveryDetail finishDetail = desList.stream().filter(el -> el.getDetailType() == 1).findAny().orElse(null);
            // 原料
            List<PackDeliveryDetail> materialList = desList.stream().filter(el -> el.getDetailType() == 0).collect(Collectors.toList());
            // 其他付费信息
            List<OrderCost> orderCosts = orderCostService.selectByMainId(packOrderId);
            // 总费用
            BigDecimal totalMoney = BigDecimal.ZERO;
            // 累加耗材的库存成本
            for (PackDeliveryDetail material : materialList){
                // 商品库存
                Stock stock = iStockService.selectById(material.getStockId());
                // 耗损比率
                BigDecimal rate = material.getLossRate();
                BigDecimal actWeight = NumberUtil.mul(material.getWeight(), NumberUtil.add(rate, 1));
                // 所选库存的成本单价（裸价 + 其他费用）
                BigDecimal costWeight = stock.getCostWeight();
                totalMoney = NumberUtil.add(totalMoney, NumberUtil.mul(costWeight, actWeight));
            }
            // 累加其他费用
            if(CollectionUtil.isNotEmpty(orderCosts)){
                BigDecimal orderCostSum = orderCosts.stream().map(OrderCost::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
                totalMoney = NumberUtil.add(totalMoney, orderCostSum);
            }
            // 成品的包装材料
            List<AgentDeliveryDetailPack> finishMaterials = detailPackService.selectByDetailId(finishDetail.getId());
            // 归属蔬菜成本的包装
            List<AgentDeliveryDetailPack> gMaterial = new ArrayList<>();
            // 归属包装成本的包装
            List<AgentDeliveryDetailPack> pMaterial = new ArrayList<>();
            // 如果包装材料不是空的，按照归属分类
            if(CollectionUtil.isNotEmpty(finishMaterials)){
                Map<Integer, List<AgentDeliveryDetailPack>> listMap = finishMaterials.stream().collect(Collectors.groupingBy(r -> r.getPackBelong()));
                gMaterial = CollectionUtil.isEmpty(listMap.get(0)) ? gMaterial : listMap.get(0);
                pMaterial = CollectionUtil.isEmpty(listMap.get(1)) ? pMaterial : listMap.get(1);
            }
            // 如果归属蔬菜成本的包装材料不为空，则需要把这部分钱合计到蔬菜成本中
            if(CollectionUtil.isNotEmpty(gMaterial)){
                BigDecimal packageCost = gMaterial.stream().map(AgentDeliveryDetailPack::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
                // 累加包装费用
                totalMoney = totalMoney.add(packageCost);
            }
            // 如果是正常加工，原料包装需要合计到成品蔬菜成本中
            if(packOrder.getPackType() == 1){
                for (PackDeliveryDetail cons : materialList){
                    // 包装材料也要加入到合成品的成本中
                    BigDecimal packageCost = cons.getMaterials().stream().map(AgentDeliveryDetailPack::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
                    // 累加包装费用
                    totalMoney = totalMoney.add(packageCost);
                }
            }
            // 成本/重量
            BigDecimal costWeight = totalMoney.divide(finishDetail.getWeight(), 6, RoundingMode.HALF_UP);
            try {
                stockService.updateStockByDetailId(costWeight, finishDetail.getId(), packOrderId, BigDecimal.ZERO);
            } catch (Exception e) {
                log.error("更新库存成本失败!{} {} {}", costWeight, finishDetail.getId(), packOrderId);
                throw new RuntimeException(e);
            }
        }                                                                                                                                                                                                                                                                              
    }

    @Override
    public int allocateTeams(List<PackDeliveryTeam> po) {
        packDeliveryTeamService.add(po);
        return 1;
    }

    @Override
    public List<AccountDetails> canPaymentList(PackCanPayPO po) {
        return baseMapper.canPaymentList(po);
    }

    /**
     * 删除主方法
     * @param packDelivery
     * @return
     */
    private R deleteMethod(PackDelivery packDelivery) throws Exception {
        // 删除原订单的其他费用
        log.info("删除原订单的其他费用:{}", packDelivery.getDocNo());
        QueryWrapper<OrderCost> orderCostQueryWrapper = new QueryWrapper();
        orderCostQueryWrapper.eq("main_id", packDelivery.getId());
        orderCostService.getBaseMapper().delete(orderCostQueryWrapper);

        // 删除原订单的商品
        QueryWrapper<PackDeliveryDetail> detailQuery = new QueryWrapper();
        detailQuery.eq("delivery_id", packDelivery.getId());
        List<PackDeliveryDetail> details = deliveryDetailService.getBaseMapper().selectList(detailQuery);
        if (CollectionUtils.isNotEmpty(details)){
            // 订单下商品的id集合
            List<Long> detailIds = details.stream().map(PackDeliveryDetail::getId).collect(Collectors.toList());
            log.info("删除订单下的商品列表:{}", JSON.toJSONString(detailIds));
            QueryWrapper<PackDeliveryDetail> detailQueryWrapper = new QueryWrapper();
            detailQueryWrapper.eq("delivery_id", packDelivery.getId());
            deliveryDetailService.getBaseMapper().delete(detailQueryWrapper);

//            log.info("删除订单下的商品列表下的包装材料:{}", JSON.toJSONString(detailIds));
//            QueryWrapper<AgentDeliveryDetailPack> materialQuery = new QueryWrapper();
//            materialQuery.in("detail_id", detailIds);
//            detailPackService.getBaseMapper().delete(materialQuery);

            // 删除原订单的商品的其他费用
            log.info("删除原订单的商品的其他费用:{}", JSON.toJSONString(detailIds));
            QueryWrapper<OrderCost> detailCost = new QueryWrapper();
            detailCost.in("main_id", detailIds);
            orderCostService.getBaseMapper().delete(detailCost);
            // 删除包装材料
            detailPackService.deleteByDetailId(detailIds, 0);
            // 释放原料的库存
            for (PackDeliveryDetail material : details) {
                stockService.releaseStockByDetailId(packDelivery.getId(), material.getId(), 2);
            }
        }
        // 删除库存流水
        iStockFlowService.deleteByOrderNo(packDelivery.getDocNo());
        return R.status(true);
    }
}
